﻿using System.Collections.Generic;
using System.Text;

namespace Infrastructure.DbUtility
{
    public class QueryOptions
    {
        private const string MSSQLPROVIDER = "System.Data.SqlClient";
        private Dictionary<string, object> dictMssqlOptions = new Dictionary<string, object>();
        private StringBuilder builder = null;
        private string provider = string.Empty;

        #region
        public int ROWCOUNT
        {
            private get { return (int)dictMssqlOptions["ROWCOUNT"]; }
            set { ChangeOption("ROWCOUNT", value); }
        }
        public int TIMEOUT
        {
            private get { return (int)dictMssqlOptions["TIMEOUT"]; }
            set { ChangeOption("TIMEOUT", value); }
        }
        #endregion

        #region Advanced
        public bool ARITHABORT
        {
            private get { return (bool)dictMssqlOptions["ARITHABORT"]; }
            set { ChangeOption("ARITHABORT", value); }
        }
        public bool CONCAT_NULL_YIELDS_NULL
        {
            private get { return (bool)dictMssqlOptions["CONCAT_NULL_YIELDS_NULL"]; }
            set { ChangeOption("CONCAT_NULL_YIELDS_NULL", value); }
        }
        #endregion

        #region ANSI
        public bool ANSI_DEFAULTS
        {
            private get { return (bool)dictMssqlOptions["ANSI_DEFAULTS"]; }
            set { ChangeOption("ANSI_DEFAULTS", value); }
        }
        public bool QUOTED_IDENTIFIER
        {
            private get { return (bool)dictMssqlOptions["QUOTED_IDENTIFIER"]; }
            set { ChangeOption("QUOTED_IDENTIFIER", value); }
        }
        public bool ANSI_PADDING
        {
            private get { return (bool)dictMssqlOptions["ANSI_PADDING"]; }
            set { ChangeOption("ANSI_PADDING", value); }
        }
        public bool ANSI_NULL_DFLT_ON
        {
            private get { return (bool)dictMssqlOptions["ANSI_NULL_DFLT_ON"]; }
            set { ChangeOption("ANSI_NULL_DFLT_ON", value); }
        }
        public bool ANSI_WARNINGS
        {
            private get { return (bool)dictMssqlOptions["ANSI_WARNINGS"]; }
            set { ChangeOption("ANSI_WARNINGS", value); }
        }
        public bool IMPLICIT_TRANSACTIONS
        {
            private get { return (bool)dictMssqlOptions["IMPLICIT_TRANSACTIONS"]; }
            set { ChangeOption("IMPLICIT_TRANSACTIONS", value); }
        }
        public bool ANSI_NULLS
        {
            private get { return (bool)dictMssqlOptions["ANSI_NULLS"]; }
            set { ChangeOption("ANSI_NULLS", value); }
        }
        public bool CURSOR_CLOSE_ON_COMMIT
        {
            private get { return (bool)dictMssqlOptions["CURSOR_CLOSE_ON_COMMIT"]; }
            set { ChangeOption("CURSOR_CLOSE_ON_COMMIT", value); }
        }
        #endregion

        public bool OptionChanged
        {
            get { return provider == MSSQLPROVIDER && builder != null && builder.Length > 0; }
        }

        public object this[string key]
        {
            set
            {
                if (provider == MSSQLPROVIDER) dictMssqlOptions[key] = value;
            }
        }
        internal QueryOptions(string provider)
        {
            this.provider = provider;
            if (this.provider == MSSQLPROVIDER) InitMssqlOptions();
        }

        private void InitMssqlOptions()
        {
            dictMssqlOptions.Add("ROWCOUNT", 0);
            dictMssqlOptions.Add("TIMEOUT", 0);
            dictMssqlOptions.Add("ARITHABORT", true);//
            dictMssqlOptions.Add("CONCAT_NULL_YIELDS_NULL", true);//
            dictMssqlOptions.Add("ANSI_DEFAULTS", true);//
            dictMssqlOptions.Add("QUOTED_IDENTIFIER", true);//
            dictMssqlOptions.Add("ANSI_PADDING", true);//
            dictMssqlOptions.Add("ANSI_NULL_DFLT_ON", true);//
            dictMssqlOptions.Add("ANSI_WARNINGS", true);//
            dictMssqlOptions.Add("IMPLICIT_TRANSACTIONS", false);//
            dictMssqlOptions.Add("ANSI_NULLS", true);//
            dictMssqlOptions.Add("CURSOR_CLOSE_ON_COMMIT", false);//
        }

        private void ChangeOption(string key, object value)
        {
            if (this.provider == MSSQLPROVIDER && dictMssqlOptions.ContainsKey(key))
            {
                if (dictMssqlOptions[key].ToString() != value.ToString())
                {
                    dictMssqlOptions[key] = value;
                    builder.AppendLine(GetOptionSetupStatement(key, value));
                }
            }
        }

        private string GetOptionSetupStatement(string key, object value)
        {
            switch (key)
            {
                case "ROWCOUNT": return string.Format("set rowcount {0}", ROWCOUNT);
                case "QUOTED_IDENTIFIER": return string.Format("set quoted_identifier {0}", QUOTED_IDENTIFIER ? "on" : "off");
                case "CONCAT_NULL_YIELDS_NULL": return string.Format("set concat_null_yields_null {0}", CONCAT_NULL_YIELDS_NULL ? "on" : "off");
                case "ARITHABORT": return string.Format("set arithabort {0}", ARITHABORT ? "on" : "off");
                case "ANSI_DEFAULTS": return string.Format("set ansi_defaults {0}", ANSI_DEFAULTS ? "on" : "off");
                case "ANSI_NULL_DFLT_ON": return string.Format("set ansi_null_dflt_on {0}", ANSI_NULL_DFLT_ON ? "on" : "off");
                case "ANSI_PADDING": return string.Format("set ansi_padding {0}", ANSI_PADDING ? "on" : "off");
                case "ANSI_WARNINGS": return string.Format("set ansi_warnings {0}", ANSI_WARNINGS ? "on" : "off");
                case "ANSI_NULLS": return string.Format("set ansi_nulls {0}", ANSI_NULLS ? "on" : "off");
                case "CURSOR_CLOSE_ON_COMMIT": return string.Format("set cursor_close_on_commit {0}", CURSOR_CLOSE_ON_COMMIT ? "on" : "off");
                case "IMPLICIT_TRANSACTIONS": return string.Format("set implicit_transactions {0}", IMPLICIT_TRANSACTIONS ? "on" : "off");
            }
            return string.Empty;
        }

        public string ToStatements()
        {
            return builder.ToString();
        }

        public void CommitChanges()
        {
            builder = new StringBuilder();
        }
    }
}
